
                /*********************************************
                **                                          **
                **                                          **
                **               gp.i.asgn.l.b2.C           **
                **                                          **
                **                                          **
                *********************************************/
                /*********************************************
                **                                          **
                **         Author Jean-Marc Adamo           **
                **       Copyright (C) 1997-2008 JMA        **
                *********************************************/


/*
1.14.2. Assignment and indirect Access Global:
        *global_d_ptr = *global_s_ptr.

Such an assignment involves reading a remote data via
the global pointer global_s_ptr and writing this data
to a remote location via the global pointer global_d_ptr.

The rhs pointer must always be set with Sdf::NOCP in order
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
to allow blocking reading only.This allow the library to
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
automatically synchronize the end of reading with the start 
of subsequent writing

The way the lhs pointer set informs the library whether or 
not writing is blocking.

When the lhs pointer is set with Sdf::NOCP, writing blocking. 
Control returns from the assignment statement only when writing 
has been completed.

When the lhs pointer is set with th pointer ot a RWCtrl record 
control returns immediately from the assignment. The completion 
event is asynchronously handled by a handler that the programmer 
has passed to the global pointer via the RWCtrl record at pointer 
construction.

A notable particular case occurs when the lhs global pointer 
refers to a local object. (into the process) 
            ^^^^^^^^^^^^
In this case control returns from the assignment statement after 
writing has been completed and the completion handler (if one 
has been provided) has been executed. Therefore, in this case,
writing works as a blocking writing whether or not a RWCtrl 
record has been passed to the global pointer at definition.


In the sample code below, reading and writing are blocking:
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*global_d_ptr = *global_s_ptr is an assignement using global 
pointers that copies an integer from the previous-rank process 
to the local process (circularly).

Access to data in reading is indirect: the data adress is computed 
on the fly by rwloc_fct. It is direct in writing. The local pointer 
to destination  is turned into a global by using a special constructor 
intended to this purpose. Writing have been made non 
blocking since a pointer to a RWCtrl record is passed to the global
destination pointer. However, it is actually blocking since writing 
occurs locally. Moreover, the handler passed to the RWCtrl record is 
executed before control returns from the assignment.

*/

#include "arch.h"

Global_id gid1;
Global_id gid2;
Coll_id cid1, cid2;

void init_gid(int, char **){
   gid1.set();
   gid2.set();
   cid1.set();
   cid2.set();
   fprintf(Sdf::trace, "node%d: gid1.tag=%d, gid2.tag=%d, cid1.tag=%d, cid2.tag=%d\n",
                Sdf::PROC_ID, gid1.get(), gid2.get(), cid1.get(), cid2.get());
   fflush(Sdf::trace);
}

int *source_data_ptr;
int count;

void wcs_handler(HRW_rcd *ptr){
   fprintf(Sdf::trace, "node%d: global-writing's over on call side\n", Sdf::PROC_ID);
   fprintf(Sdf::trace, "node%d: wcs_handler, rem_proc=%d, d_ptr=%d, g-sz=%d, th_ptr=%d, hndlr_ptr=%d, hndlr_d_ptr=%d\n",
           Sdf::PROC_ID, ptr->get_remote_proc(),
           ptr->get_data_ptr(), ptr->get_given_size(),
           ptr->get_thread_ptr(), ptr->get_hndlr_ptr(),
           ptr->get_hndlr_data_ptr());
   fflush(Sdf::trace);
}

void rts_handler(void *){
   fprintf(Sdf::trace, "node%d: global-reading's over on target side\n", Sdf::PROC_ID);
   fflush(Sdf::trace);
}

int *rloc_fct(IDH_rcd *ptr){
   fprintf(Sdf::trace, "node%d: loc_fct, src_proc=%d, sz=%d, sent-sz=%d, tag_ev=%d, tag_av=%d, offset=%d, rarg0=%d, rarg1=%d\n",
           Sdf::PROC_ID, ptr->get_remote_proc(),
           ptr->get_given_size(), ptr->get_sent_size(),
           ptr->get_tag_ev(), ptr->get_tag_av(),
           ptr->get_offset(), ptr->get_rarg(0),
           ptr->get_rarg(1));
   fflush(Sdf::trace);
   ptr->set_handler(rts_handler, 0);
   return source_data_ptr;
}

class Root_thread: public Thread{
   public:
        Root_thread()
                : Thread((Tmf0_ptr)&Root_thread::body){}

        void body(){
           fprintf(Sdf::trace, "from node%d: this is my rank\n", Sdf::PROC_ID);
           fflush(Sdf::trace);
           fflush(Sdf::trace);
           int source_data;
           int dest_data;
           source_data_ptr = &source_data;

           source_data  = Sdf::PROC_ID;
           dest_data    = 100+Sdf::PROC_ID; //to check value change in trace

           fprintf(Sdf::trace, "node%d: s=%d, d=%d\n",
                    Sdf::PROC_ID, source_data, dest_data);
           fflush(Sdf::trace);

           Global<int> global_s(gid1, rloc_fct);
           Sdf::barrier(cid1);

           count = 0;
           Star<int> global_s_ptr((Sdf::PROC_ID+Sdf::PROC_NB-1)%Sdf::PROC_NB, global_s, 
                                  (unsigned long)0, Sdf::NORA, Sdf::NOAP, Sdf::NOCP); 
           Star<int> global_d_ptr(gid2, &dest_data);
            //local pointer &dest_data is turned into a Global pointer with Sdf::DIR
            //access type to data

           int rarg_r[2] = {50,100};    //just to check values in trace
           global_s_ptr.set_rarg(rarg_r);

           RWCtrl ctrl_w;
           ctrl_w.set_hndlr_ptr(wcs_handler);
           ctrl_w.set_hndlr_data_ptr(0);
           ctrl_w.set_thread_ptr(Sdf::this_thread);
           global_d_ptr.set_ctrl_ptr(&ctrl_w);
             //to make writing through global_d_ptr nonblocking 

           *global_d_ptr = *global_s_ptr;
             //global writing is nonblocking because set_ctrl_ptr above.
             //However, it is actually blocking since writing occurs locally.
             //the handler passed to ctrl_w is executed before control returns
             //from the assignment.

           Sdf::barrier(cid2);
              //Global syncro before printing

           fprintf(Sdf::trace, "node%d: s=%d, d=%d\n",
                        Sdf::PROC_ID, source_data, dest_data);
           fflush(Sdf::trace);
        }
};

MAIN(Root_thread, init_gid, Sdf::empty, Sdf::empty)

